package com.aco.fatureapp.activity;

import java.text.DecimalFormat;
import java.util.List;

import roboguice.inject.ContentView;
import roboguice.inject.InjectView;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import br.com.ac.fatureweb.integration.billing.LogLeituraVO.TypeRetencao;
import br.com.ac.fatureweb.integration.business.CalcularConsumo;
import br.com.ac.fatureweb.integration.business.CalcularConsumo.ValidarLeitura;
import br.com.ac.fatureweb.integration.utilitary.NumberUtils;

import com.aco.fatureapp.R;
import com.aco.fatureapp.activity.MeteringActivity.CallImovelAsyncTask.RetornoVO;
import com.aco.fatureapp.activity.SearchMeteringActivity.TypeFilter;
import com.aco.fatureapp.fragments.NoteFragment;
import com.aco.fatureapp.fragments.NoteFragment.NoteListener;
import com.aco.fatureapp.model.Help;
import com.aco.fatureapp.model.Imovel;
import com.aco.fatureapp.model.Roteiro;
import com.aco.fatureapp.model.RoteiroConfig;
import com.aco.fatureapp.model.TypeReturnFind;
import com.aco.fatureapp.model.billing.Fatura;
import com.aco.fatureapp.model.billing.LogLeitura;
import com.aco.fatureapp.model.printer.Billing;
import com.aco.fatureapp.model.printer.PrinterResumo;
import com.aco.fatureapp.printer.libs.Printer2;
import com.aco.fatureapp.service.SrvBilling;
import com.aco.fatureapp.service.SrvImportRoute;
import com.aco.fatureapp.service.SrvMetering;
import com.aco.fatureapp.service.exception.BillingException;
import com.aco.fatureapp.utilitary.CallAsyncTask;
import com.aco.fatureapp.utilitary.DataUtils;
import com.aco.fatureapp.utilitary.GpsUtils;
import com.aco.fatureapp.utilitary.Utils;
import com.google.inject.Inject;

@ContentView(R.layout.activity_metering)
public class MeteringActivity extends BaseActivity implements NoteListener {

	protected static final int ID_TELA_PESQUISA = 10;

	protected static final int ID_TELA_OCORRENCIA = 20;

	protected static final int ID_TELA_CONFIRMACAO = 30;

	private static final int ID_TELA_CORRECAO = 40;

	@InjectView(R.id.txtInscricao)
	TextView mTxtInscricao;

	@InjectView(R.id.txtCodificacao)
	TextView mTxtCodificacao;

	@InjectView(R.id.txtCliente)
	TextView mTxtCliente;

	@InjectView(R.id.txtEndereco)
	TextView mTxtEndereco;

	@InjectView(R.id.txtHidrometro)
	TextView mTxtHidrometro;

	@InjectView(R.id.txtEconomias)
	TextView mTxtEconomias;

	@InjectView(R.id.txtLeitura)
	TextView mTxtLeitura;

	@InjectView(R.id.txtCodOcorrencia)
	TextView mTxtCodOcorrencia;

	@InjectView(R.id.txtDscOcorrencia)
	TextView mTxtDscOcorrencia;

	@InjectView(R.id.txtValorFatura)
	TextView mTxtValorFatura;

	@InjectView(R.id.txtQtdCorrecoes)
	TextView mTxtQtdCorrecoes;

	@InjectView(R.id.txtQtdImpressoes)
	TextView mTxtQtdImpressoes;

	@InjectView(R.id.txtTipoRetencao)
	TextView mTxtTipoRetencao;

	@InjectView(R.id.txtQuantitadeEconomia)
	TextView mTxtQuantitadeEconomia;

	/*
	 * Botões
	 */
	@InjectView(R.id.btnOcorrencia)
	Button mBtnOcorrencia;

	@InjectView(R.id.btnClearOcorrencia)
	Button mBtnClearOcorrencia;

	@InjectView(R.id.btnSearch)
	Button mBtnSearch;

	@InjectView(R.id.btnPrevious)
	Button mBtnPrevious;

	@InjectView(R.id.btnNext)
	Button mBtnNext;

	@InjectView(R.id.btnSave)
	Button mBtnSave;

	@InjectView(R.id.btnPrint)
	Button mBtnPrint;

	private RoteiroConfig mRoteiroConfig;

	private Imovel mEntity;

	private LogLeitura mLogLeitura;

	private Integer mTotalLeitura;

	private GpsUtils mGpsUtils;

	/*
	 * Serviço
	 */
	@Inject
	private SrvMetering mSrvMetering;

	@Inject
	private SrvBilling mSrvBilling;

	Printer2 mPrinter = new Printer2();

	// Guardar no cache para evitar muita consultar no banco.
	Long mDataFaturamento = null;

	@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		try {
			/**
			 * Registrando Eventos
			 */
			mBtnPrevious.setOnClickListener(leituraAnterior());
			mBtnNext.setOnClickListener(proximaLeitura());
			mBtnSearch.setOnClickListener(pesquisar());
			mBtnPrint.setOnClickListener(print());
			mBtnSave.setOnClickListener(save());
			mBtnOcorrencia.setOnClickListener(filterOcorrencia());

			// Buscar a configuração do roteiro
			mRoteiroConfig = new SrvImportRoute().getRoteiroConfig();

			// Buscar a primeira leitura caso exista.
			mEntity = mSrvMetering.getPrimeiraLeitura();

			if (mEntity != null) {

				// Popular campos da tela.
				parseValueEntityForScreen();
			}

			// Desabilitar o botão de gravação.
			disableMetering();
		}
		catch (Exception ex) {
			gerarMensagem(ex);
		}
	}

	/**
	 * Verificar quais condições deverá restringuir a leitura.
	 */
	private void disableMetering() {

		boolean disable = false;

		if (mRoteiroConfig != null && mRoteiroConfig.isEncerrado()) {
			mBtnSave.setEnabled(false);
			Utils.alert(MeteringActivity.this, "Roteiro está encerrado.", null);
			disable = true;
		}
		else {
			mBtnSave.setEnabled(true);
			disable = false;
		}

		if (!disable) {
			if (mDataFaturamento == null) {
				mDataFaturamento = mSrvBilling.getDataFaturamento();
			}

			boolean isPrazoEncerrado = mSrvMetering
					.validarPrazoLeitura(mDataFaturamento);

			if (isPrazoEncerrado) {
				mBtnSave.setEnabled(false);
				Utils.alert(MeteringActivity.this,
						"Fora do prazo de leitura ou "
								+ "data do aparelho está errada.", null);
			}
			else {
				mBtnSave.setEnabled(true);
			}
		}
	}

	private void gerarMensagem(Exception ex) {
		Utils.alert(this, "Oops! algum insperado aconteceu. \n Detalhes: \n "
				+ ex.getLocalizedMessage(), closeMetering());
	}

	private android.content.DialogInterface.OnClickListener closeMetering() {
		return new Dialog.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				finish();
			}
		};
	}

	/**
	 * Pesquisar ocorrência.
	 *
	 * @return
	 */
	private OnClickListener filterOcorrencia() {
		return new OnClickListener() {

			/*
			 * (non-Javadoc)
			 *
			 * @see android.view.View.OnClickListener#onClick(android.view.View)
			 */
			@Override
			public void onClick(View v) {
				new CallAsyncTask(MeteringActivity.this, false)
						.execute(new CallAsyncTask.Action() {

							/*
							 * (non-Javadoc)
							 *
							 * @see
							 * com.aco.fatureapp.utilitary.CallAsyncTask.Action
							 * #execute()
							 */
							@Override
							public String execute() {
								startActivityForResult(new Intent(
										"IF_SEARCH_HELP"), ID_TELA_OCORRENCIA);
								return null;
							}
						});

			}
		};
	}

	private void parseValueEntityForScreen() {

		setTitle(mEntity.getOrdemRoteiro(), mTotalLeitura);

		mTxtInscricao.setText(mEntity.getInscricao().toString());
		mTxtCodificacao.setText(mEntity.getCodificacao());
		mTxtCliente.setText(mEntity.getNomeResponsavel());
		mTxtEndereco.setText(mEntity.getEndereco());
		mTxtHidrometro.setText(mEntity.getNumeroHidrometro());
		mTxtEconomias.setText(mEntity.getCategoria());

		// Somar a quantidade de economias.
		mTxtQuantitadeEconomia.setText(mSrvBilling.getQuantidadeEconomia(
				mEntity.getInscricao()).toString());

		Utils.startBluetooth(MeteringActivity.this);

		// Deixar em cache pra guardar as coordenadas atualizadas.
		if (mGpsUtils == null) {
			mGpsUtils = new GpsUtils(MeteringActivity.this);
			mGpsUtils.startLocation();
		}

		// Verificar se o Gps está habilitado.
		// mGpsUtils.verifyIsProviderEnabled();

		// Colocar em cache para não fazer a consulta várias vezes.
		if (mTotalLeitura == null) {
			mTotalLeitura = mSrvMetering.buscarOrdemUltimaLeitura();
		}

		mLogLeitura = mSrvBilling.getLogLeitura(mEntity.getInscricao());

		parseValueBillingForScreen();
	}

	private void desHabilitarColetaLeitura() {
		mTxtCodOcorrencia.setEnabled(false);
		mTxtLeitura.setEnabled(false);
		mBtnOcorrencia.setVisibility(View.GONE);
	}

	private void habilitarColetaLeitura() {
		mTxtCodOcorrencia.setEnabled(true);
		mTxtLeitura.setEnabled(true);
		mBtnOcorrencia.setVisibility(View.VISIBLE);
	}

	private void parseValueBillingForScreen() {
		if (mLogLeitura != null) {
			if (mLogLeitura.getLeitura() != null) {
				mTxtLeitura.setText(mLogLeitura.getLeitura().toString());
			}
			else {
				mTxtLeitura.setText("");
			}
			mTxtValorFatura.setText(NumberUtils.formatMoney(mLogLeitura
					.getValorConta()));
			mTxtQtdCorrecoes.setText(mLogLeitura.getQtdeCorrecao().toString());

			if (mLogLeitura.getCodOcorrencia1() != null) {
				mTxtCodOcorrencia.setText(mLogLeitura.getCodOcorrencia1()
						.toString());
			}
			mTxtQtdImpressoes
					.setText(mLogLeitura.getQtdeImpressao().toString());

			if (mLogLeitura.getContaRetida() != null) {
				TypeRetencao typeRetencao = TypeRetencao.valueOf(mLogLeitura
						.getContaRetida());
				if (typeRetencao != null) {
					mTxtTipoRetencao.setText(typeRetencao.getDescricao());
				}
				else {
					mTxtTipoRetencao.setText("");
				}
			}
			else {
				mTxtTipoRetencao.setText("");
			}

			// Pegar a descrição da ocorrência.
			mTxtDscOcorrencia.setVisibility(View.GONE);

			if (mLogLeitura.getCodOcorrencia1() != null) {
				mTxtDscOcorrencia
						.setText(mSrvMetering
								.getDescricaoOcorrencia(mLogLeitura
										.getCodOcorrencia1()));
				mTxtDscOcorrencia.setVisibility(View.VISIBLE);
			}

			desHabilitarColetaLeitura();
			mBtnSave.setVisibility(View.GONE);
			mBtnPrint.setVisibility(View.VISIBLE);
		}
		else {

			mBtnSave.setVisibility(View.VISIBLE);
			mBtnPrint.setVisibility(View.GONE);

			mTxtLeitura.setText("");
			mTxtValorFatura.setText("");
			mTxtQtdCorrecoes.setText("");
			mTxtCodOcorrencia.setText("");
			mTxtQtdImpressoes.setText("");
			mTxtTipoRetencao.setText("");

			/*
			 * Se o imóvel não possuir hidrômetro, então você informa a
			 * ocorrência: "COD_OCORRENCIA":2,
			 * "DES_OCORRENCIA":"IMOVEL SEM HIDROM.", "FLG_OCORRENCIA":"0", -
			 * leitura não realizada "FLG_COBRANCA":"1", - cobrada a média
			 * "EMITIR_CONTA":"S" - emite conta O consumo recebe a media do
			 * imóvel: - campo "CONSUMO_MEDIO" no objeto do array ficha
			 * (Imovel).
			 */
			if (!mEntity.isTemHidrometro()) {
				Help ocorrencia = mSrvMetering.getOcorrencia(2L);

				mTxtCodOcorrencia.setText(ocorrencia.codigo.toString());
				mTxtDscOcorrencia.setText(ocorrencia.descricao);

				mTxtDscOcorrencia.setVisibility(View.VISIBLE);

				desHabilitarColetaLeitura();
			}
			else {
				habilitarColetaLeitura();

				mTxtDscOcorrencia.setVisibility(View.GONE);
			}

			mBtnSave.setText("Gravar");

		}
	}

	private void setTitle(final Integer ordemAtual, Integer ordemFinal) {
		try {
			final DecimalFormat df = new DecimalFormat("###");

			if (ordemAtual != null && ordemFinal != null) {
				getActionBar().setTitle(
						"Roteiro: " + df.format(ordemAtual) + "/"
								+ df.format(ordemFinal));
			}
			else {
				ordemFinal = mSrvMetering.buscarOrdemUltimaLeitura();
				getActionBar()
						.setTitle("Roteiro: 001/" + df.format(ordemFinal));
			}
		}
		catch (final Exception e) {
			getActionBar().setTitle("Roteiro");
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onCreateOptionsMenu(final android.view.Menu menu) {
		super.onCreateOptionsMenu(menu);
		Utils.hideTouch(MeteringActivity.this);

		final MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.action_bar_menu_metering, menu);

		getActionBar().setDisplayHomeAsUpEnabled(true);

		return true;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem)
	 */
	@Override
	public boolean onMenuItemSelected(final int featureId, final MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home: {
			finish();
			return true;
		}
		case R.id.menu_camera: {
			if (mRoteiroConfig != null && !mRoteiroConfig.isEncerrado()) {
				Utils.hideTouch(MeteringActivity.this);
				Intent intent = new Intent("IF_PHOTO_GALERY");
				intent.putExtra(Imovel.getTableName(Imovel.class), mEntity);

				startActivity(intent);
			}
			else {
				Utils.alert(MeteringActivity.this, "Roteiro está encerrado.",
						null);
			}

			return true;
		}
		case R.id.menu_note: {
			if (mRoteiroConfig != null && !mRoteiroConfig.isEncerrado()) {
				Utils.hideTouch(MeteringActivity.this);
				final DialogFragment frgNote = new NoteFragment();
				Bundle arg = new Bundle();

				arg.putSerializable(LogLeitura.getTableName(LogLeitura.class),
						mLogLeitura);

				frgNote.setArguments(arg);
				frgNote.show(getFragmentManager(), "NOTE_DIALOG");
			}
			else {
				Utils.alert(MeteringActivity.this, "Roteiro está encerrado.",
						null);
			}

			return true;
		}
		case R.id.menu_previous_unfinished: {
			Utils.hideTouch(MeteringActivity.this);
			previousNotCompleted();
			return true;
		}
		case R.id.menu_next_unfinished: {
			Utils.hideTouch(MeteringActivity.this);
			nextNotCompleted();
			return true;
		}
		case R.id.menu_fix_bill: {
			if (mRoteiroConfig != null && !mRoteiroConfig.isEncerrado()) {
				Utils.hideTouch(MeteringActivity.this);
				Intent intent = new Intent("IF_ERASE_METERING");
				intent.putExtra(Imovel.getTableName(Imovel.class),
						mEntity.getInscricao());
				startActivityForResult(intent, ID_TELA_CORRECAO);
			}
			else {
				Utils.alert(MeteringActivity.this, "Roteiro está encerrado.",
						null);
			}

			return true;
		}
		case R.id.menu_show_bill: {
			Utils.hideTouch(MeteringActivity.this);
			Intent intent = new Intent("IF_SHOW_BILL");
			intent.putExtra(Imovel.getTableName(Imovel.class),
					mEntity.getInscricao());

			startActivity(intent);
			return true;
		}
		}
		return true;
	}

	@Override
	protected void onActivityResult(final int requestCode,
			final int resultCode, final Intent data) {

		if (requestCode != 0) {
			switch (requestCode) {
			case ID_TELA_PESQUISA: {
				if (data != null) {
					final TypeReturnFind typeReturnFind = (TypeReturnFind) data
							.getExtras().get(TypeReturnFind.SEARCH_VALUE);

					// implements
					if (typeReturnFind != null
							&& typeReturnFind.mTypeFilter != null) {

						TypeFilter typeFilter = TypeFilter
								.valueOf(typeReturnFind.mTypeFilter);

						Imovel entity = mSrvMetering.findLeitura(typeFilter,
								typeReturnFind.mValue);

						Utils.hideTouch(MeteringActivity.this);

						if (entity == null) {
							Utils.alert(
									MeteringActivity.this,
									"Não foi encontrado resultado para o valor informado na pesquisa.",
									null);
							return;
						}

						mEntity = entity;

						parseValueEntityForScreen();
					}
				}
				break;
			}
			case ID_TELA_OCORRENCIA: {
				if (data != null) {
					Object help = data.getExtras().get(
							SearchHelpActivity.VALUE_RETURN);

					if (help != null) {
						Help retorno = (Help) help;
						mTxtCodOcorrencia.setText(retorno.codigo.toString());
						mTxtDscOcorrencia.setText(retorno.descricao);
						mTxtDscOcorrencia.setVisibility(View.VISIBLE);
					}
				}
				Utils.hideTouch(MeteringActivity.this);

				break;
			}
			case ID_TELA_CONFIRMACAO: {
				if (data != null) {
					Object help = data.getExtras().get(
							ConfirmLessMeteringActivity.VALUE_RETURN);

					if (help != null) {
						Help retorno = (Help) help;
						mTxtCodOcorrencia.setText(retorno.codigo.toString());
						mTxtDscOcorrencia.setText(retorno.descricao);
						mTxtDscOcorrencia.setVisibility(View.VISIBLE);
					}
				}
				Utils.hideTouch(MeteringActivity.this);

				break;
			}
			case ID_TELA_CORRECAO: {

				if (data != null) {

					final Integer retorno = (Integer) data.getExtras().get(
							EraseMeteringActivity.RETURN);

					if (retorno != null) {
						mLogLeitura = null;

						parseValueBillingForScreen();

						Utils.hideTouch(MeteringActivity.this);
					}
				}
				break;
			}
			}
		}

		super.onActivityResult(requestCode, resultCode, data);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see roboguice.activity.RoboActivity#onDestroy()
	 */
	@Override
	protected void onDestroy() {
		mSrvMetering.closeDB();
		super.onDestroy();
	}

	private OnClickListener pesquisar() {
		return new OnClickListener() {

			@Override
			public void onClick(final View v) {
				Utils.hideTouch(MeteringActivity.this);
				final Intent intent = new Intent("IF_SEARCH_METERING");
				startActivityForResult(intent, ID_TELA_PESQUISA);
			}
		};
	}

	private OnClickListener leituraAnterior() {
		return new OnClickListener() {

			@Override
			public void onClick(final View v) {
				if (mEntity != null && mEntity.getOrdemRoteiro() != null) {

					final Imovel imovelAnterior = mSrvMetering
							.leituraAnterior(mEntity.getOrdemRoteiro());

					if (imovelAnterior != null) {

						mEntity = imovelAnterior;

						parseValueEntityForScreen();

						Utils.hideTouch(MeteringActivity.this);
					}
					else {
						Utils.alert(MeteringActivity.this,
								"Essa é a primeira leitura.", null);
					}
				}
			}
		};
	}

	private OnClickListener proximaLeitura() {
		return new OnClickListener() {

			@Override
			public void onClick(final View v) {
				executeNextMetering();
			}
		};
	}

	private void previousNotCompleted() {
		new CallImovelAsyncTask(MeteringActivity.this, TypeAction.PREVIOUS)
				.execute();
	}

	private void nextNotCompleted() {
		new CallImovelAsyncTask(MeteringActivity.this, TypeAction.NEXT)
				.execute();
	}

	private OnClickListener save() {
		return new OnClickListener() {

			@Override
			public void onClick(final View v) {
				Utils.hideTouch(MeteringActivity.this);

				final LeituraValidator leituraValidator = new LeituraValidator()
						.validate(mTxtLeitura, mTxtCodOcorrencia);

				if (leituraValidator.isValida) {
					new BuildBillingTask().execute(leituraValidator);
				}
			}
		};
	}

	private OnClickListener print() {
		return new OnClickListener() {

			@Override
			public void onClick(final View v) {

				final String macPrinter = mSrvMetering.getMacImpressora();

				if (macPrinter == null) {
					Utils.alert(MeteringActivity.this,
							"Impressora padrão não está configurada!", null);
					return;
				}

				CallAsyncTask callAsyncTask = new CallAsyncTask(
						MeteringActivity.this, true);

				mPrinter = new Printer2();

				callAsyncTask.execute(new CallAsyncTask.Action() {

					@Override
					public String execute() {

						try {
							Billing billing = mSrvBilling.getFaturaImpressao(
									mEntity.getInscricao(),
									usuarioLogado.getId());

							Printer2.imprimirContaEmPaginas(macPrinter,
									billing, MeteringActivity.this, mPrinter,
									mEntity.getInscricao(), mLogLeitura);

							return null;
						}
						catch (Exception ex) {

							Log.e("Impressao_conta", ex.getLocalizedMessage());

							return ex.getMessage();
						}
					}
				});
			}
		};
	}

	private class BuildBillingTask extends
			AsyncTask<LeituraValidator, Void, TypeReturnProcess> {

		ProgressDialog progressDialog;

		@Override
		protected TypeReturnProcess doInBackground(LeituraValidator... params) {
			try {
				boolean impressoraDesativada = mSrvMetering.isImpressoraAtiva();

				Fatura fatura = mSrvBilling.gerarFatura(params[0], mEntity,
						mGpsUtils, usuarioLogado.getId(), impressoraDesativada);

				// TODO colocar numa thread de impressão no postexecute e não
				// deixar sair da tela até terminar a impressão.

				// Só mandar para impressão se a impressora estiver ativa.
				if (!impressoraDesativada) {

					try {
						final String macPrinter = mSrvMetering
								.getMacImpressora();

						// Só imprimir a conta que não estiver com o flag de
						// retenção.
						if (macPrinter != null
								&& (fatura.getLogLeitura().getContaRetida() == null || fatura
										.getLogLeitura().getContaRetida() <= 0)) {

							Printer2.imprimirContaEmPaginas(macPrinter,
									fatura.getBilling(), MeteringActivity.this,
									mPrinter, mEntity.getInscricao(),
									mLogLeitura);

							if (mSrvMetering.isImprimirResumo()) {

								SystemClock.sleep(2000);

								if (mPrinter.checkBth(MeteringActivity.this,
										macPrinter)) {

									List<PrinterResumo> lstPrinterResumo = mSrvMetering
											.getLstPrinterResumo();

									Roteiro roteiro = mSrvMetering.getRoteiro();

									// Imprimir resumo.
									Printer2.imprimirResumo(
											roteiro.getNumero(),
											mEntity.getIdCarga(),
											Utils.getImei(MeteringActivity.this),
											DataUtils
													.formatarCompetencia(roteiro
															.getCompetencia()),
											lstPrinterResumo,
											mPrinter.mBth.ostream);

									mSrvMetering
											.markBillPrinting(lstPrinterResumo);

									mPrinter.closeBth();

									SystemClock.sleep(2000);
								}
							}
						}
					}
					catch (Exception ex) {
						Log.e("ERROR - IMPRESSAO-GERAR CONTA",
								ex.getLocalizedMessage());
					}
				}

				return new TypeReturnProcess(fatura, TypeConclusion.SUCESS,
						"Conta gerada com sucesso!");
			}
			catch (BillingException ex) {
				return new TypeReturnProcess(TypeConclusion.ERROR,
						ex.getMessage());
			}
		}

		@Override
		protected void onPreExecute() {
			progressDialog = new ProgressDialog(MeteringActivity.this);
			progressDialog.setTitle("iFature Mobile");
			progressDialog.setMessage("Aguarde, gerando a fatura "
					+ "e imprimindo.");
			progressDialog.setCancelable(false);
			progressDialog.show();
		}

		@Override
		protected void onPostExecute(TypeReturnProcess result) {
			progressDialog.dismiss();

			if (result != null) {

				switch (result.typeConclusion) {
				case SUCESS: {
					mLogLeitura = result.fatura.getLogLeitura();

					// TODO: Enviar conta para impressão, depois colocar numa
					// thread de impressão e identificar se a impressão de uma
					// conta ou um resumo.
					// Billing billing = result.fatura.getBilling();

					// Mostrar a mensagem de sucesso e enviar para próxima
					// leitura.
					showMessageSuccessfullyProcess(result.message);

					break;
				}
				case ERROR: {

					Utils.alert(MeteringActivity.this,
							"Erro no processamento da conta. \n Detalhes: "
									+ result.message, null);
					break;
				}
				}
			}
		}
	}

	private void showMessageSuccessfullyProcess(String message) {
		Utils.alert(MeteringActivity.this, message,
				new Dialog.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						executeNextMetering();
					}
				});
	}

	private void executeNextMetering() {
		if (mEntity != null && mEntity.getOrdemRoteiro() != null) {

			final Imovel proximoImovel = mSrvMetering.proximaLeitura(mEntity
					.getOrdemRoteiro());

			if (proximoImovel != null) {

				mEntity = proximoImovel;

				parseValueEntityForScreen();

				Utils.hideTouch(MeteringActivity.this);
			}
			else {
				parseValueEntityForScreen();

				Utils.alert(MeteringActivity.this, "Essa é a última leitura.",
						null);
			}
		}
	}

	/**
	 * Executar as validações necessárias para leitura informada.
	 *
	 * @author aldivone
	 *
	 */
	public class LeituraValidator {

		public Long leitura;

		public Long codOcorrencia;

		public boolean isValida;

		public LeituraValidator() {
			super();
		}

		public LeituraValidator(boolean isValida) {
			super();
			this.isValida = isValida;
		}

		public LeituraValidator(Long leitura, Long codOcorrencia,
				boolean isValida) {
			super();
			this.leitura = leitura;
			this.codOcorrencia = codOcorrencia;
			this.isValida = isValida;
		}

		public LeituraValidator validate(TextView txtLeitura,
				TextView txtCodOcorrencia) {

			if (txtLeitura.getText().toString().length() == 0
					&& txtCodOcorrencia.getText().toString().length() == 0) {

				Utils.alert(
						MeteringActivity.this,
						"O Campo \"Leitura\" ou \"Ocorrência\" é obrigatório e deve ser informado.",
						null);

				return new LeituraValidator(false);
			}

			// Validar o código da Ocorrência.
			if (txtCodOcorrencia.getText().toString().length() > 0) {
				Long codOcorrencia2 = Long.valueOf(txtCodOcorrencia.getText()
						.toString());
				if (codOcorrencia2.equals(0L)) {
					Utils.alert(
							MeteringActivity.this,
							"Ocorrência não permitida. Ela é gerada pelo sistema.",
							null);
					return new LeituraValidator(false);
				}

				Help ocorrencia = mSrvMetering.getOcorrencia(codOcorrencia2);

				if (ocorrencia == null) {
					Utils.alert(
							MeteringActivity.this,
							"Ocorrência informada não é valida. Favor informar"
									+ " outra ou consultar no botão de pesquisar ao lado.",
							null);
					return new LeituraValidator(false);
				}
			}

			if (txtCodOcorrencia.getText().toString().length() > 0) {
				Long leitura = null;

				if (txtLeitura.getText().length() > 0) {
					leitura = Long.valueOf(txtLeitura.getText().toString());
				}
				return new LeituraValidator(leitura,
						Long.valueOf(txtCodOcorrencia.getText().toString()),
						true);
			}

			final Long leitura = Long.valueOf(txtLeitura.getText().toString());

			// Validar leitura atual maior que leitura anterior e
			// Validar Leitura atual igual a leitura anterior...
			final ValidarLeitura validarLeitura = CalcularConsumo
					.validarLeitura(mEntity.isTemHidrometro(), leitura,
							mEntity.getLeituraAnterior(), null);

			if (validarLeitura.isLeituraIgual) {
				/*
				 * 3.2.2 – a leitura atual for igual à leitura anterior:
				 *
				 * 3.2.2.1 – código 0(leitura normal) – consumo zerado , o
				 * consumo deve ser calculado de acordo com a configuração
				 * encontrada no campo "FAT_CONSZERADO" do objeto de
				 * configuração:
				 *
				 * 3.2.2.1.1 - FAT_CONSZERADO = 0, consumo recebe a média do
				 * imóvel;
				 *
				 * 3.2.2.1.2 - FAT_CONSZERADO = 1, consumo recebe o mínimo da
				 * tarifa.
				 *
				 * 3.2.2.2 – código 50(hidrômetro parado), o consumo recebe a
				 * média do imóvel.
				 */
				Utils.alert(
						MeteringActivity.this,
						"Leitura atual igual a Leitura anterior. Hidrômetro parado?",
						"Sim", "Não", new Dialog.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								dialog.dismiss();

								new BuildBillingTask()
										.execute(new LeituraValidator(leitura,
												50L, true));
							}
						}, new Dialog.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								dialog.dismiss();
								new BuildBillingTask()
										.execute(new LeituraValidator(leitura,
												validarLeitura.codOcorrencia,
												true));
							}
						}, true);

				return new LeituraValidator(false);
			}

			if (validarLeitura.isLeituraMenor) {
				/*
				 * 3.2.1 – a leitura atual for menor que a anterior, poderá
				 * informar as ocorrências:
				 *
				 * 3.2.1.1 – código 51 (verificar leit. Ant). o imóvel volta
				 * para ser analisado;
				 *
				 * 3.2.1.2 – código 52 (hidrômetro Invertido) - o consumo é
				 * calculado leitura anterior – leitura atual;
				 *
				 * 3.2.1.3 – código 53 (hidrômetro virado) - o consumo é
				 * calculado (leitura atual + 10000) - leitura anterior;
				 *
				 * 3.2.1.4 – código 54(hidrômetro invertido/virado) o consumo é
				 * calculado (leitura anterior + 10000) - leitura atual.
				 */

				// / Perguntar qual ocorrência deve usar.
				new CallAsyncTask(MeteringActivity.this, false)
						.execute(new CallAsyncTask.Action() {

							@Override
							public String execute() {
								final Intent intent = new Intent(
										"IF_CONFIRM_METERING");
								startActivityForResult(intent,
										ID_TELA_CONFIRMACAO);
								return null;
							}
						});

				return new LeituraValidator(false);
			}

			Long codOcorrencia = null;

			if (txtCodOcorrencia.getText().toString().length() > 0) {
				codOcorrencia = Long.valueOf(txtCodOcorrencia.getText()
						.toString());
			}

			if (codOcorrencia == null) {
				codOcorrencia = validarLeitura.codOcorrencia;
			}

			return new LeituraValidator(leitura, codOcorrencia, true);
		}
	}

	private class TypeReturnProcess {
		public Fatura fatura;

		public TypeConclusion typeConclusion;

		public String message;

		public TypeReturnProcess(Fatura fatura, TypeConclusion typeConclusion,
				String message) {
			super();
			this.fatura = fatura;
			this.typeConclusion = typeConclusion;
			this.message = message;
		}

		public TypeReturnProcess(TypeConclusion typeConclusion, String message) {
			super();
			this.typeConclusion = typeConclusion;
			this.message = message;
		}
	}

	enum TypeAction {
		PREVIOUS, NEXT;
	}

	private enum TypeConclusion {
		ERROR, SUCESS;
	}

	class CallImovelAsyncTask extends
			android.os.AsyncTask<Void, Void, RetornoVO> {
		ProgressDialog mProgressDialog;
		private Context mContext;
		private TypeAction mTypeAction;

		public CallImovelAsyncTask(Context mContext, TypeAction typeAction) {
			super();
			this.mContext = mContext;
			this.mTypeAction = typeAction;
		}

		@Override
		protected void onPreExecute() {
			mProgressDialog = new ProgressDialog(mContext);
			mProgressDialog.setTitle("iFature Mobile");
			mProgressDialog.setMessage("Aguarde, executando sua solicitação.");
			mProgressDialog.show();
		}

		@Override
		protected RetornoVO doInBackground(Void... params) {
			try {
				RetornoVO retornoVO = new RetornoVO();

				switch (mTypeAction) {
				case PREVIOUS: {
					if (mEntity != null && mEntity.getOrdemRoteiro() != null) {
						final Imovel previousImovel = mSrvMetering
								.previousNotCompleted(mEntity.getOrdemRoteiro());

						retornoVO.imovel = previousImovel;
					}
					break;
				}
				case NEXT: {
					if (mEntity != null && mEntity.getOrdemRoteiro() != null) {
						final Imovel nextImovel = mSrvMetering
								.nextNotCompleted(mEntity.getOrdemRoteiro());

						retornoVO.imovel = nextImovel;
					}
					break;
				}
				}

				return retornoVO;
			}
			catch (Exception ex) {
				return new RetornoVO(ex.getMessage(), null);
			}
		}

		@Override
		protected void onPostExecute(RetornoVO result) {
			mProgressDialog.dismiss();

			if (result != null && result.message != null) {
				Utils.alert(mContext,
						"Erro no processamento da solicitação. \n Detalhes: "
								+ result, null);
			}

			if (result != null && result.message == null) {

				switch (mTypeAction) {

				case PREVIOUS: {
					Imovel previousImovel = result.imovel;

					if (previousImovel != null) {

						mEntity = previousImovel;

						parseValueEntityForScreen();
					}
					else {
						Utils.alert(MeteringActivity.this,
								"Essa é a primeira leitura sem faturamento.",
								null);
					}
					break;
				}
				case NEXT: {
					Imovel nextImovel = result.imovel;

					if (nextImovel != null) {

						mEntity = nextImovel;

						parseValueEntityForScreen();
					}
					else {
						Utils.alert(MeteringActivity.this,
								"Essa é a última leitura sem faturamento.",
								null);
					}

					break;
				}
				}

			}
		}

		class RetornoVO {
			public String message;

			public Imovel imovel;

			public RetornoVO(String message, Imovel imovel) {
				super();
				this.message = message;
				this.imovel = imovel;
			}

			public RetornoVO() {
				super();
			}
		}
	}

	/* ############# CALLBACK PARA O DIALOG DE OBSERVAÇÃO ############# */

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.aco.fatureapp.fragments.NoteFragment.NoteListener#onDialogPositiveClick
	 * (android.app.DialogFragment)
	 */
	@Override
	public void onDialogPositiveClick(DialogFragment dialog) {
		final NoteFragment frg = (NoteFragment) dialog;

		if (frg.getTxtNote().getText() != null && mLogLeitura != null) {
			mLogLeitura.setObservacao(frg.getTxtNote().getText().toString());
		}
	}

}
